/*****************************************************************************
 *   Copyright 2011 ZHUANG Yuan              	                             *
 *   SudokuITS as Final Year Project for BScCS, City University of Hong Kong *
 *                                      									 *
 *   Licensed under the Apache License, Version 2.0 (the "License");         *
 *   you may not use this file except in compliance with the License.        *
 *   You may obtain a copy of the License at                                 *
 *                                                                           *
 *   http://www.apache.org/licenses/LICENSE-2.0                              *
 *                                                                           *
 *   Unless required by applicable law or agreed to in writing, software     *
 *   distributed under the License is distributed on an "AS IS" BASIS,       *
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.*
 *   See the License for the specific language governing permissions and     *
 *   limitations under the License.                                          *
 *****************************************************************************/

package android.sudoku.its.expert;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import android.sudoku.its.util.GameVariables;

/**
 * A matrix showing applicable strategies for all undetermined cell
 * @author 51158282
 *
 */
public class ApplicableStrategyMatrix {	
	// An list of arraylist of length 81 to store applicable strategy number for each cell.
	private List<List<Integer>> applicableStrategyMatrix;
	private Strategies strategies;
	
	
	public ApplicableStrategyMatrix(int[][] twoDClues, List<List<Integer>> candidateMatrix) {
		strategies = new Strategies();
		generateApplicableStrategyMatrix(twoDClues, candidateMatrix);
	}

	/**
	 * Initialize Applicable Strategy Matrix when the game is first started
	 * @param clues				a 2d array containing clues on the game board
	 * @param candidateMatrix	a list of arraylist representing the Candidate Matrix
	 */
	public void generateApplicableStrategyMatrix(int[][] clues, List<List<Integer>> candidateMatrix) {
		// Initialize Applicable Strategy Matrix
		applicableStrategyMatrix = new ArrayList<List<Integer>>();
		
		// Check cell by cell what strategies are available
		for (int row = 0; row < GameVariables.HOUSE_SIZE; row++) {
			for (int col = 0; col < GameVariables.HOUSE_SIZE; col++) {
				// Create an arraylist to store applicable strategy for one cell
				List<Integer> applicableStrategyForOneCell = new ArrayList<Integer>();
				
				if (clues[row][col] == 0) {	// if the cell is an undetermined cell
					if (candidateMatrix.get(row * GameVariables.HOUSE_SIZE + col).size() == 1) { 
						// If a cell only has one candidate, 
						// applicable strategies for this cell could be Full House and Naked Single.
						// Note that only one strategy can be applicable in this case.										
						if (strategies.isFullHouseApplicable(clues, row, col)) // if full house is applicable
							applicableStrategyForOneCell.add(GameVariables.FULL_HOUSE_INDEX);
						else if (strategies.isNakedSingleApplicable(clues, row, col)) // if naked single is applicable
							applicableStrategyForOneCell.add(GameVariables.NAKED_SINGLE_INDEX);						
					}
					if (candidateMatrix.get(row * GameVariables.HOUSE_SIZE + col).size() == 2) { 
						// If a cell has two candidates, applicable strategies for this cell could be Naked Pair.
						// Note that multiple strategies can be applicable in this case.					
						if(strategies.isNakedPairApplicable(candidateMatrix, row, col)) 
							applicableStrategyForOneCell.add(GameVariables.NAKED_PAIR_INDEX);															
					}			
					
					// If a cell has multiple candidates, applicable strategies for this cell could be Hidden Single
					
					// Check if Hidden Single is applicable	
					if (candidateMatrix.get(row * GameVariables.HOUSE_SIZE + col).size() > 1) {			
						if (strategies.isHiddenSingleApplicable(candidateMatrix, row, col) != 0) 	
							applicableStrategyForOneCell.add(GameVariables.HIDDEN_SINGLE_INDEX);													
					}					 				
				}		
				
				applicableStrategyMatrix.add(applicableStrategyForOneCell);
					
			}
		}
		
		// Update Applicable Strategy Matrix for Hidden Pair
		applicableStrategyMatrix = strategies.updateASMForHiddenPair(candidateMatrix, applicableStrategyMatrix);
		
		// TODO Update Applicable Strategy Matrix for Locked Candidate
	}
	
	public List<Integer> getApplicableStrategyByCellFunc(int nRow, int nCol) {
		return applicableStrategyMatrix.get(nRow * GameVariables.HOUSE_SIZE + nCol);
	}

	public List<List<Integer>> getApplicableStrategyMatrix() {
		return applicableStrategyMatrix;
	}
	
	/**
	 * TODO delete this is a test function upon finishing
	 * @return
	 */
	public int[][] getIntArrAsm() {
		int[][] intArrAsm = new int[GameVariables.PUZZLE_LENGTH][GameVariables.HOUSE_SIZE];
		
		for (int i=0; i<GameVariables.PUZZLE_LENGTH; i++) {
			for (int j=0; j<GameVariables.HOUSE_SIZE; j++) {
				intArrAsm[i][j] = 0;
			}
		}
		
		for (int i = 0; i < GameVariables.PUZZLE_LENGTH; i++) {
			Iterator<Integer> iterator = applicableStrategyMatrix.get(i).iterator();		
		    for (int j = 0; j < applicableStrategyMatrix.get(i).size(); j++) {
		    	int value = iterator.next().intValue();
		    	intArrAsm[i][value] = value;	    	
		    }
		}
				
		return intArrAsm;
	}
	
}